﻿using CPPEI.Coolzon.Common;
using CPPEI.Coolzon.Event.NCL;
using CPPEI.Coolzon.Metadata;
using CPPEI.Coolzon.UI;
using CPPEI.Coolzon.UI.Data;
using CPPEI.Coolzon.UI.Event;
using CPPEI.Coolzon.UI.Views;
using CPPEI.Coolzon.UI.Views.Windows;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Threading;

namespace Coolvis.Console.Theme.MainViewControl
{
    /// <summary>
    /// ZoomView.xaml 的交互逻辑
    /// </summary>
    public partial class ZoomView : UserControl
    {
        private double _scaleX;
        private double _scaleY;
        private Point _startPoint;
        private Point _endPoint;

        private DispatcherTimer _dispatcherTimer;
        //private BorderWindow _borderWindow;
        /// <summary>
        /// 屏幕坐标
        /// </summary>
        private Point _oldPoint;
        private bool _canMove = true;
        private bool _borderStop = false;
        private CPPEI.Coolzon.UI.Part _screenPart;
        private bool _isStartMagnifier = false;
        private DateTime _startTimer;
        private bool _isStartPen = false;
        private bool _isResetScene = false;

        private VisualBrush partBrush;
        private ImageSource partImageSource;
        public Scene _Scene { get; set; }

        private Point _mousePos;
        private double _moveOffsetXY = 20;
        private List<Line> _lineList = new List<Line>();

        public ZoomView()
        {
            InitializeComponent();

            OnInitEvent();
        }

        public void Close()
        {
            OnDestoryEvent();
        }

        #region 方法
        private void SetPartImageSource()
        {
            partImageSource = GetImageSource();
            _isResetScene = false;
            canvas.Background = new ImageBrush(partImageSource);
        }

        private ImageSource GetImageSource()
        {
            _border.Visibility = Visibility.Hidden;
            RenderTargetBitmap rtb = new RenderTargetBitmap((int)canvas.ActualWidth, (int)canvas.ActualHeight, 96, 96, PixelFormats.Default);
            rtb.Render(canvas);
            _border.Visibility = Visibility.Visible;
            return rtb;
        }
        private bool IsMouseMoving(Point oldPoint, Point newPoint)
        {
            Point screenPoint = PointToScreen(newPoint);
            double oldPi = Math.Sqrt(Math.Pow(oldPoint.X, 2) + Math.Pow(oldPoint.Y, 2));
            double newPi = Math.Sqrt(Math.Pow(screenPoint.X, 2) + Math.Pow(screenPoint.Y, 2));
            if (Math.Abs(oldPi - newPi) > 10) return true;
            return false;
        }

        /// <summary>
        /// 设置蒙版位置
        /// </summary>
        /// <returns></returns>
        private void SetBorderWindowPoint()
        {
            double left = Canvas.GetLeft(this._ctlRectDragMask);
            double top = Canvas.GetTop(this._ctlRectDragMask);

            double tempLeft = _oldPoint.X - this._ctlRectDragMask.Width / 2;
            double tempTop = _oldPoint.Y - this._ctlRectDragMask.Height / 2;

            if (tempLeft < _startPoint.X)
            {
                Canvas.SetLeft(this._ctlRectDragMask, _startPoint.X);
            }
            else if (tempLeft + this._ctlRectDragMask.Width > _endPoint.X)
            {
                Canvas.SetLeft(this._ctlRectDragMask, _endPoint.X - this._ctlRectDragMask.Width);
            }
            else
            {
                Canvas.SetLeft(this._ctlRectDragMask, tempLeft);
            }
            if (tempTop + this._ctlRectDragMask.Height > _endPoint.Y)
            {
                Canvas.SetTop(this._ctlRectDragMask, _endPoint.Y - this._ctlRectDragMask.Height);
            }
            else
            {
                Canvas.SetTop(this._ctlRectDragMask, tempTop);
            }
        }
        private void Swap(AreaPart source, AreaPart target)
        {
            if (source != null && target != null)
            {
                //是否允许区域互换
                if (_Scene.IsAllowSwapArea)
                {
                    CPPEI.Coolzon.Common.EventBus.Instance.Publish(new SwapAreaEvent(_Scene.Name, source.Name, target.Name));
                }
            }
        }
        /// <summary>
        /// 根据坐标获取区域
        /// </summary>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <param name="fromScreen">为1时，x,y代表屏幕坐标</param>
        /// <returns></returns>
        private AreaPart GetAreaPartAtPoint(double x, double y, int fromScreen = 0)
        {
            CPPEI.Coolzon.UI.Views.RenderView renderView = (CPPEI.Coolzon.UI.Views.RenderView)UIContext.Current.RenderView;
            ScenePart scenePart = (ScenePart)renderView.GetCurrentPart();
            Point elementPoint = new Point(x, y);
            if (fromScreen == 1)
            {
                elementPoint = this.PointFromScreen(new Point(x, y));
            }
            Point scalePoint = new Point(elementPoint.X / _scaleX, elementPoint.Y / _scaleY);
            AreaPart area = (AreaPart)scenePart.GetRootArea(scalePoint);

            if (this._ctlRectDragMask.Tag != null && area != null)
            {
                AreaPart sourceArea = this._ctlRectDragMask.Tag as AreaPart;

                double leftRight = sourceArea.XLeft - area.XLeft;
                //int leftRight = sourceArea.XLeft < area.XLeft ? 1 : 0;
                if (leftRight < 0)
                {
                    if (elementPoint.X < (area.XLeft + area.Width / 2) * _scaleX)
                    {
                        area = scenePart.GetLeftRootArea(area);
                    }
                }
                else if (leftRight > 0)
                {
                    if (elementPoint.X > (area.XLeft + area.Width / 2) * _scaleX)
                    {
                        area = scenePart.GetRightRootArea(area);
                    }
                }
                else
                {
                    area = null;
                }
            }
            return area;
        }

        private void CreateScaleView(AreaPart area)
        {
            if (area == null)
            {
                return;
            }

            _startPoint = PointToScreen(new Point(0, 0));
            _endPoint = PointToScreen(new Point(this.ActualWidth, this.ActualHeight));

            this._ctlRectDragMask.Width = area.ActualWidth * _scaleX;
            this._ctlRectDragMask.Height = area.ActualHeight * _scaleY;
            double left = _oldPoint.X - this._ctlRectDragMask.Width / 2;
            double top = this._ctlRectDragMask.Height / 2;

            Canvas.SetLeft(this._ctlRectDragMask, left);
            Canvas.SetTop(this._ctlRectDragMask, top);
            System.Diagnostics.Debug.WriteLine(string.Format("set {0},{1},{2},{3}", left, top, this._ctlRectDragMask.Width, this._ctlRectDragMask.Height));

            this._ctlRectDragMask.Visibility = System.Windows.Visibility.Visible;

            this._ctlRectDragMask.Tag = area;
        }
        private void ScollToPos(Point point)
        {
            double borderLeft = point.X - _border.Width / 2;
            double borderTop = point.Y - _border.Height / 2;

            SetBorderRect(ref borderLeft, ref borderTop);

            double tLeft = borderLeft / _scaleX;
            double tTop = borderTop / _scaleY;

            Canvas.SetLeft(_border, borderLeft);
            Canvas.SetTop(_border, borderTop);

            CPPEI.Coolzon.UI.Views.RenderView renderView = (CPPEI.Coolzon.UI.Views.RenderView)UIContext.Current.RenderView;
            renderView.ScrollToPos(tLeft, tTop);
        }

        private void SetBorderRect(ref double borderLeft, ref double borderTop)
        {
            if (borderLeft + _border.Width > this.ActualWidth)
            {
                borderLeft = this.ActualWidth - _border.Width;
            }
            if (borderTop + _border.Height > this.ActualHeight)
            {
                borderTop = this.ActualHeight - _border.Height;
            }
            if (borderLeft < 0.0)
            {
                borderLeft = 0.0;
            }
            if (borderTop < 0.0)
            {
                borderTop = 0.0;
            }
        }
        public void SetSceneView()
        {
            CPPEI.Coolzon.UI.Views.RenderView renderView = (CPPEI.Coolzon.UI.Views.RenderView)UIContext.Current.RenderView;
            _screenPart = renderView.GetCurrentPart();
            _scaleX = canvas.ActualWidth / _screenPart.XWidth;
            _scaleY = canvas.ActualHeight / _screenPart.XHeight;

            if (_screenPart != null)
            {
                if (_Scene != (_screenPart as ScenePart).SceneMatadata)
                {
                    _Scene = (_screenPart as ScenePart).SceneMatadata;

                    partBrush = new VisualBrush(_screenPart);
                    //RenderOptions.SetCachingHint(partBrush, CachingHint.Cache);
                    //RenderOptions.SetCacheInvalidationThresholdMaximum(partBrush, 2.0);
                    //RenderOptions.SetCacheInvalidationThresholdMinimum(partBrush, 0.5);
                    partBrush.Stretch = Stretch.Fill;

                    canvas.Background = partBrush;

                    partImageSource = null;
                }

                AddLine();

                Rect viewRect = renderView.GetViewRegionInScene();

                double borderLeft = viewRect.Left * _scaleX;
                double borderTop = viewRect.Top * _scaleY;
                SetBorderRect(ref borderLeft, ref borderTop);
                Canvas.SetLeft(_border, borderLeft);
                Canvas.SetTop(_border, borderTop);
                _border.Width = viewRect.Width * _scaleX;
                _border.Height = viewRect.Height * _scaleY;
            }
            else
            {
                Logger.ErrorToTag(Library.LogTAG, "GetCurrentPart为空");
            }
        }

        private void canvas_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            CPPEI.Coolzon.UI.Views.RenderView renderView = (CPPEI.Coolzon.UI.Views.RenderView)UIContext.Current.RenderView;
            if(renderView == null)
            {
                return;
            }

            _screenPart = renderView.GetCurrentPart();
            if (_screenPart != null)
            {
                _scaleX = canvas.ActualWidth / _screenPart.XWidth;
                _scaleY = canvas.ActualHeight / _screenPart.XHeight;

                AddLine();

                Rect viewRect = renderView.GetViewRegionInScene();

                double borderLeft = viewRect.Left * _scaleX;
                double borderTop = viewRect.Top * _scaleY;
                SetBorderRect(ref borderLeft, ref borderTop);
                Canvas.SetLeft(_border, borderLeft);
                Canvas.SetTop(_border, borderTop);
                _border.Width = viewRect.Width * _scaleX;
                _border.Height = viewRect.Height * _scaleY;
            }
        }

        private void AddLine()
        {
            ClearLines();

            List<CPPEI.Coolzon.UI.Part> partList = (_screenPart as ScenePart).GetPartList();
            Dispatcher.BeginInvoke(DispatcherPriority.Render, new Action(() =>
            {
                foreach (CPPEI.Coolzon.UI.Part part in partList)
                {

                    double partLeft = Canvas.GetLeft(part) * _scaleX;
                    double partWidth = part.ActualWidth * _scaleX;
                    double partHeight = part.ActualHeight * _scaleY;

                    Line line = new Line();

                    line.X1 = partLeft + partWidth;
                    line.Y1 = Canvas.GetTop(part) * _scaleY;

                    line.X2 = line.X1;
                    line.Y2 = line.Y1 + partHeight;

                    line.Stroke = new SolidColorBrush(Colors.White);
                    line.StrokeDashArray = new DoubleCollection { 3, 2 };
                    line.StrokeThickness = 3;

                    canvas.Children.Add(line);

                    _lineList.Add(line);
                }
            }));
        }

        private void ClearLines()
        {
            foreach (Line line in _lineList)
            {
                canvas.Children.Remove(line);
            }
            _lineList.Clear();
        }

        private void CloseBorderWindow()
        {
            this._ctlRectDragMask.Tag = null;
            this._ctlRectDragMask.Visibility = System.Windows.Visibility.Hidden;
        }

        #endregion

        #region 场景视图事件

        private void nextScene_Click(object sender, RoutedEventArgs e)
        {
            e.Handled = true;
            NextSceneDown();
        }
        private void nextScene_MouseDown(object sender, MouseButtonEventArgs e)
        {
            e.Handled = true;
            NextSceneDown();
        }
        private void NextSceneDown()
        {
            Scene nextScene = SolutionUtil.GetNextDisplayflowNode(UIContext.Current.Solution, _Scene);
            if (nextScene == null) return;

            OpenSceneArgs openSceneArgs = new OpenSceneArgs();
            openSceneArgs.ParametersString.Add("sys:isresetviewstate", "true");
            NCLEventBus.PublishAsync(
                new NCLOpenSceneEvent(SwitchMode.Replace, "", nextScene.Name, openSceneArgs));
        }
        #endregion
    }
}
